#include "sgl_draw_circle.h"
#include "stdio.h"

void sgl_draw_circle_solid_noaa(sgl_surf_t *surf, int16_t cx, int16_t cy, int r, sgl_color_t color)
{
#if (SGL_CONFIG_DRAW_ALGO == 0)
    int16_t path[SGL_CONFIG_DRAW_STACK_MAX];
    memset(path, 0, SGL_CONFIG_DRAW_STACK_MAX*2);
    int middle = sgl_figure_circle_path(r, path);
    for (int y = 0 ; y < r; y ++) {
        if( y <= middle) {            
            sgl_draw_hline(surf, cx - path[y], cy + y - 1,  (path[y])*2, color);
            sgl_draw_hline(surf, cx - path[y], cy - y,  (path[y])*2, color);
            sgl_draw_hline(surf, cx - y, cy - path[y] + 1, (y)*2, color);
            sgl_draw_hline(surf, cx - y, cy + path[y] - 2, (y)*2, color);
        }
    }
#else
    int f = 1 - r;
    int diameter = 2*r;
    int ddF_x = 0;
    int ddF_y = - diameter;
    int y = 0;
    int x = r;
    while(y < x) {
        if(f >= 0) {
            x--;
            ddF_y += 2;
            f += ddF_y;
        }
        y++;
        ddF_x += 2;
        sgl_draw_hline(surf, cx-y, cy-x+1, 2*y, color);
        sgl_draw_hline(surf, cx-y, cy+x-2, 2*y, color);
        sgl_draw_hline(surf, cx-x+1, cy-y, 2*x - 2, color);
        sgl_draw_hline(surf, cx-x+1, cy+y-1, 2*x - 2, color);
        f += ddF_x + 1;
    }
#endif
}

void sgl_draw_circle_solid(sgl_surf_t *surf, int16_t cx, int16_t cy, int r, sgl_color_t fg_color, sgl_color_t bg_color)
{
#if (SGL_CONFIG_DRAW_ALGO == 0)
    int mix = 0;
    int16_t path[SGL_CONFIG_DRAW_STACK_MAX];
    memset(path, 0, SGL_CONFIG_DRAW_STACK_MAX*2);
    int middle = sgl_figure_circle_path(r, path);
    for (int y = 0 ; y < r; y ++) {
        if( y <= middle) {
            mix = (SGL_RENDER_CIRCLE(r, y-1));
            
            sgl_draw_hline(surf, cx - path[y], cy + y - 1,  (path[y])*2, fg_color);
            sgl_draw_point(surf, cx + path[y] - 1, cy + y - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - path[y], cy + y - 1, sgl_color_mixer(fg_color, bg_color, mix));

            sgl_draw_hline(surf, cx - path[y], cy - y,  (path[y])*2, fg_color);
            sgl_draw_point(surf, cx + path[y] - 1, cy - y, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - path[y], cy - y, sgl_color_mixer(fg_color, bg_color, mix));

            sgl_draw_hline(surf, cx - y, cy - path[y] + 1, (y)*2, fg_color);
            sgl_draw_point(surf, cx - y, cy - path[y], sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx + y - 1, cy - path[y], sgl_color_mixer(fg_color, bg_color, mix));

            sgl_draw_hline(surf, cx - y, cy + path[y] - 2, (y)*2, fg_color);
            sgl_draw_point(surf, cx + y - 1, cy + path[y] - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - y, cy + path[y] - 1, sgl_color_mixer(fg_color, bg_color, mix));
        }
    }
#else
    int f = 1 - r;
    int diameter = 2*r;
    int ddF_x = 0;
    int ddF_y = - diameter;
    int y = 0;
    int x = r;
    sgl_color_t aa_color;
    //sgl_color_t edge_color = sgl_color_mixer(fg_color, bg_color, 128);
    //sgl_draw_hline(surf, cx, cy - r, 1, edge_color);
    //sgl_draw_hline(surf, cx, cy + r -1, 1, edge_color);
    while(y < x) {
        if(f >= 0) {
            x--;
            ddF_y += 2;
            f += ddF_y;
        }
        y++;
        ddF_x += 2;
        aa_color = sgl_color_mixer(fg_color, bg_color, - f * 128 / r);
        SGL_RENDER_ROUND_EDGE_LT(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RT(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_LB(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RB(surf, cx, cy, x, y, aa_color);
        sgl_draw_hline(surf, cx-y, cy-x+1, 2*y, fg_color);
        sgl_draw_hline(surf, cx-y, cy+x-2, 2*y, fg_color);
        sgl_draw_hline(surf, cx-x+1, cy-y, 2*x - 2, fg_color);
        sgl_draw_hline(surf, cx-x+1, cy+y-1, 2*x - 2, fg_color);
        f += ddF_x + 1;
    }
#endif
}


void sgl_draw_circle_hollow(sgl_surf_t *surf, int16_t cx, int16_t cy, int r, sgl_color_t fg_color, sgl_color_t bg_color)
{
#if (SGL_CONFIG_DRAW_ALGO == 0)
    int mix = 0;
    int16_t path[SGL_CONFIG_DRAW_STACK_MAX];
    memset(path, 0, SGL_CONFIG_DRAW_STACK_MAX*2);
    int middle = sgl_figure_circle_path(r, path);
    for (int y = 0 ; y < r; y ++) {
        if( y <= middle) {
            mix = (SGL_RENDER_CIRCLE(r, y-1));

            sgl_draw_point(surf, cx + path[y] - 1, cy + y - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - path[y], cy + y - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx + path[y] - 2, cy + y - 1, sgl_color_mixer(fg_color, bg_color, 256 - mix));
            sgl_draw_point(surf, cx - path[y] + 1, cy + y - 1, sgl_color_mixer(fg_color, bg_color, 256 - mix));

            sgl_draw_point(surf, cx + path[y] - 1, cy - y, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - path[y], cy - y, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx + path[y] - 2, cy - y, sgl_color_mixer(fg_color, bg_color, 256 -  mix));
            sgl_draw_point(surf, cx - path[y] + 1, cy - y, sgl_color_mixer(fg_color, bg_color, 256 - mix));

            sgl_draw_point(surf, cx - y, cy - path[y], sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx + y - 1, cy - path[y], sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - y, cy - path[y] + 1, sgl_color_mixer(fg_color, bg_color, 256 - mix));
            sgl_draw_point(surf, cx + y - 1, cy - path[y] + 1, sgl_color_mixer(fg_color, bg_color, 256 - mix));

            sgl_draw_point(surf, cx + y - 1, cy + path[y] - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx - y, cy + path[y] - 1, sgl_color_mixer(fg_color, bg_color, mix));
            sgl_draw_point(surf, cx + y - 1, cy + path[y] - 2, sgl_color_mixer(fg_color, bg_color, 256 - mix));
            sgl_draw_point(surf, cx - y, cy + path[y] - 2, sgl_color_mixer(fg_color, bg_color, 256 - mix));
        }
    }
#else
    int f = 1 - r;
    int diameter = 2*r;
    int ddF_x = 0;
    int ddF_y = - diameter;
    int y = 0;
    int x = r;
    sgl_color_t aa_color, edge_color = sgl_color_mixer(fg_color, bg_color, 150);
    sgl_draw_area_color(surf, cx, cy - r, cx+1, cy - r + 2, edge_color);
    sgl_draw_area_color(surf, cx, cy + r - 2, cx+1, cy + r, edge_color);
    while(y < x) {
        if(f >= 0) {
            x--;
            ddF_y += 2;
            f += ddF_y;
        }
        y++;
        ddF_x += 2;
        aa_color = sgl_color_mixer(fg_color, bg_color, - f * 128 / r);
        SGL_RENDER_ROUND_EDGE_LT(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RT(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_LB(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RB(surf, cx, cy, x, y, aa_color);
        aa_color = sgl_color_mixer(fg_color, bg_color, 255 + f * 128 / r);
        SGL_RENDER_ROUND_EDGE_LTI(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RTI(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_LBI(surf, cx, cy, x, y, aa_color);
        SGL_RENDER_ROUND_EDGE_RBI(surf, cx, cy, x, y, aa_color);
        
        f += ddF_x + 1;
    }
    sgl_draw_area_color(surf, cx - r, cy, cx - r + 2, cy, edge_color);
    sgl_draw_area_color(surf, cx + r - 1, cy, cx + r + 1, cy, edge_color);
#endif
}


void sgl_draw_thick_circle(sgl_surf_t *surf, uint16_t cx, uint16_t cy, uint16_t r, uint16_t thick, sgl_color_t color, sgl_color_t bg_color)
{
    r += (thick/2);
    uint16_t radius2 = r - thick;
    uint16_t xo[SGL_CONFIG_DRAW_STACK_MAX];
    uint16_t xi[SGL_CONFIG_DRAW_STACK_MAX];

    int32_t   D;    /* Decision Variable */
    uint16_t  CurX; /* Current X Value */
    uint16_t  CurY; /* Current Y Value */

    D = 3 - (r << 1);
    CurX = 0;
    CurY = r;

    uint16_t iterations = 0;
    // Calculate outer circle
    while (CurX <= CurY)
    {
        xo[CurX] = CurY;
        xo[CurY] = CurX;
        if (iterations < CurX)
            iterations = CurX;
        if (iterations < CurY)
            iterations = CurY;
        xi[CurX*2] = 0;
        xi[CurY*2] = 0;
        xi[CurX*2+1] = 0;
        xi[CurY*2+1] = 0;

        if (D < 0)
        {
            D += (CurX << 2) + 6;
        }
        else
        {
            D += ((CurX - CurY) << 2) + 10;
            CurY--;
        }
        CurX++;
    }

    D = 3 - (radius2 << 1);
    CurX = 0;
    CurY = radius2;
    // Calculate inner circle
    while (CurX <= CurY)
    {
        xi[CurX] = CurY;
        xi[CurY] = CurX;

        if (D < 0)
        {
            D += (CurX << 2) + 6;
        }
        else
        {
            D += ((CurX - CurY) << 2) + 10;
            CurY--;
        }
        CurX++;
    }

    // Draw horizontal lines
    for (int y = 0; y <= iterations; y++)
    {
        if (xi[y] != 0) {
            sgl_draw_hline(surf, cx + xi[y], cy - y, xo[y] - xi[y], color);
            sgl_draw_hline(surf, cx - xo[y], cy - y, xo[y] - xi[y], color);
            sgl_draw_hline(surf, cx + xi[y], cy + y, xo[y] - xi[y], color);
            sgl_draw_hline(surf, cx - xo[y], cy + y, xo[y] - xi[y], color);
            
           // sgl_draw_pixel(cx + xi[y] - 1, cy - y, sgl_color_mixer());

        }
        else
        {
            sgl_draw_hline(surf, cx - xo[y], cy - y, xo[y] + xo[y], color);
            sgl_draw_hline(surf, cx - xo[y], cy + y, xo[y] + xo[y], color);
        }
    }
}


sgl_pos_t sgl_circle_pos_by_angle(int16_t r, int16_t angle)
{
    sgl_pos_t ret;
    sgl_trig_t trig;
    trig = sgl_trig(angle * 0x4000 / 90);
    ret.y = trig.sin_h  * r / 32766;
    ret.x = trig.cos_h * r / 32766;
    return ret;
}
